﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace PaintRuler
{
    public partial class Form1 : Form
    {
        private float unit = 1.0f;// 刻度单位长度
        private const int RulerNum = 16;// 刻度尺数量 16行
        private const int ScaleNum = 20000;// 刻度尺拥有多少个小格子 101
        private float ScaleLength;// 刻度尺小格子尺寸
        private const float RulerHeight = 200;// 刻度尺高度
        private const float RulerLength = 44800;// 刻度尺长度
        private const float ScaleStart = 0;
        private const float HeavenBlank = 40;// 顶部留白
        private int StartY = 0;// 整个图像的起始位置
        private int StartY_1 = 100;// 刻度尺起始位置
        private int StartY_2 = 0;// 刻度尺结束的位置
        private int StartY_3 = 0;// 

        List<List<int>> ruler_array;
        public Form1()
        {
            InitializeComponent();
            ruler_array = new List<List<int>>();
            ruler_array.Add(new List<int> { 0, 4, 8, 12 });
            ruler_array.Add(new List<int> { 1, 5, 9, 13 });
            ruler_array.Add(new List<int> { 2, 6, 10, 14 });
            ruler_array.Add(new List<int> { 3, 7, 11, 15 });
        }
        private void DrawFunc(Graphics g)
        {
            //重置坐标
            StartY_1 = StartY + 100;
            StartY_2 = StartY_1 + Convert.ToInt32(RulerNum * RulerHeight);

            g.Clear(Color.White);
            Pen pen = new Pen(Color.Black);
            Font font = new Font("Times New Roman", 30, FontStyle.Regular);
            Font font_1 = new Font("Arial", 46, FontStyle.Bold);
            //string CMYK_str = "K";
            g.FillRectangle(Brushes.Black, 0, 0, RulerLength, HeavenBlank);
            g.DrawLine(pen, 0, HeavenBlank - 30, 0, (HeavenBlank + RulerHeight * RulerNum) * 4);
            //g.DrawString(CMYK_str, font_1, Brushes.Black, 0, StartY + HeavenBlank - 40);

            //foreach(int i in ruler_array[SwitchRulerComboBox.SelectedIndex == -1 ? 0 : SwitchRulerComboBox.SelectedIndex])
            int nThousandFont = -1;// 按1K为分割，使得显示的数字不至于过长
            for (int i = 0; i < 16; i++)
            {
                float y = StartY_1 + i * RulerHeight;
                g.DrawLine(pen, 0, y + RulerHeight, pictureBox1.Width, y + RulerHeight);
                g.DrawLine(pen, 0, y + RulerHeight / 3, pictureBox1.Width, y + RulerHeight / 3);

                float x = 0;
                int j = 0;
                while (x < pictureBox1.Width)
                {
                    x = i * unit + j * ScaleLength;
                    // 长线
                    if (j % 5 == 0)
                    {
                        g.DrawLine(pen, x, y, x, y + RulerHeight);
                        if(i == 0 && nThousandFont != ((int)x / 1000))
                        {
                            nThousandFont = (int)x / 1000;
                            g.DrawString($"+{nThousandFont}K", font_1, Brushes.Black, x, StartY + 35);
                            g.DrawLine(pen, x, StartY, x, y + RulerHeight);
                        }
                        if (j + 2 < ScaleNum)
                            g.DrawString(((i + j * 16)%1000 + 1).ToString(), font, Brushes.Black, x - 8, StartY + y + 15);
                    }
                    else
                        g.DrawLine(pen, x, y + RulerHeight, x, y + RulerHeight / 3);
                    j++;
                }
            }

            g.FillRectangle(Brushes.Black, 0, StartY_2 + 60, RulerLength, HeavenBlank);
        }
        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            ScaleLength = 16 * unit;
            pictureBox1.Size = new Size((int)RulerLength, (int)((200 + RulerNum * RulerHeight)));

            Graphics g = e.Graphics;
            DrawFunc(g);
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            Bitmap bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                DrawFunc(g);
            }
            //pictureBox1.DrawToBitmap(bitmap, pictureBox1.ClientRectangle);
            // 32转1bit
            Bitmap newbitmap = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format1bppIndexed);
            bitmap.Dispose();
            //bitmap.Save("scale_ruler_32bit.bmp", ImageFormat.Bmp);

            int index = SwitchRulerComboBox.SelectedIndex == -1 ? 0 : SwitchRulerComboBox.SelectedIndex;

            newbitmap.Save($"output\\scale_ruler_{RulerLength}_1bit.bmp", ImageFormat.Bmp);

            
            newbitmap.Dispose();
        }

        private void BtnConvert_Click(object sender, EventArgs e)
        {


            #region method1



            ////打开任一索引色的或者非索引色的图像
            //Image img = Image.FromFile("scale_ruler.bmp");
            //ImageAttributes ta = new ImageAttributes();
            ///* 下面用Graphics类改变像点颜色，是靠ImageAttributes来把
            //* 彩色变成灰度，或者颠倒黑白，用矩阵处理还是很方便
            //*/
            ////如实际发现几个简单又好用的矩阵：
            ///* float[][] mm=new float[][]{ //彩色变灰度的矩阵
            //     new float[]{0.4f, 0.4f, 0.4f, 0, 0},
            //     new float[]{0.3f, 0.3f, 0.3f, 0, 0},
            //     new float[]{0.3f, 0.3f, 0.3f, 0, 0},
            //     new float[]{0,    0,    0,    1, 0},
            //     new float[]{0,    0,    0,    0, 1}
            //};
            //float[][] mm1=new float[][]{ //彩色反相的矩阵
            //     new float[]{0,    0.3f, 0.5f, 0, 0},
            //     new float[]{0.5f, 0.3f, 0.5f, 0, 0},
            //     new float[]{0.5f, 0.4f, 0,    0, 0},
            //     new float[]{0,    0,    0,    1, 0},
            //     new float[]{0,    0,    0,    0, 1}
            //};
            //*/
            ///*
            //float[][] mm2 = new float[][]{ //彩色变反相灰度的矩阵
            //     new float[]{-0.4f, -0.4f, -0.4f, 0, 0},
            //     new float[]{-0.3f, -0.3f, -0.3f, 0, 0},
            //     new float[]{-0.3f, -0.3f, -0.3f, 0, 0},
            //     new float[]{1,     1,     1,     1, 0},
            //     new float[]{0,     0,     0,     0, 1}
            //};
            //*/

            //float[][] mm3 = new float[][]{// 创建颜色矩阵，将图像转换为单色
            //    new float[] { 0.299f, 0.299f, 0.299f, 0, 0 },
            //    new float[] { 0.587f, 0.587f, 0.587f, 0, 0 },
            //    new float[] { 0.114f, 0.114f, 0.114f, 0, 0 },
            //    new float[] { 0,      0,      0,      1, 0 },
            //    new float[] { 0,      0,      0,      0, 1 }
            //};


            //ColorMatrix cmt = new ColorMatrix(mm3);
            //ta.SetColorMatrix(cmt);

            ///*
            ////如果确知图像里仅有纯黑白二色，也可用ColorMap来反相，它可逐色改变
            //ColorMap map1=new ColorMap();
            //map1.OldColor=Color.Black;
            //map1.NewColor=Color.White;
            //ColorMap map2=new ColorMap();
            //map2.OldColor=Color.White;
            //map2.NewColor=Color.Black;
            //ta.SetRemapTable(new ColorMap[]{map1,map2},ColorAdjustType.Bitmap);
            //*/
            ///* 有的图像比如索引格式的位图或GIF是无法创建Graphics的，
            //* 需要新建一非索引色位图取得Graphics对象以便做画或改变像点颜色。
            //*/
            //Bitmap bmp = new Bitmap(img.Width, img.Height);
            //Graphics g = Graphics.FromImage(bmp);
            //g.DrawImage(img, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, ta);
            ////g.DrawString("Foxit PDF Reader",new Font("宋体",8),new SolidBrush(Color.White),0,0);
            //g.Dispose();
            ///* 在如下构造图像数据之前，也可以先创建一单色位图并锁定数据，
            //* 利用它现成的Stride简单计算出实际每行有效数据之后的填充字节数，而且可
            //* 在下面循环里直接写点Marshal.WriteByte(dt.Scan0,k,val);而不用数组拷贝
            //*/
            ////以下，把反相或者涂画后的像点数据每一行的每8点简单合并成1byte存储
            //int midrgb = Color.FromArgb(128, 128, 128).ToArgb();
            //int stride;//简单公式((width/8)+3)&(~3)
            //stride = (bmp.Width % 8) == 0 ? (bmp.Width / 8) : (bmp.Width / 8) + 1;
            //stride = (stride % 4) == 0 ? stride : ((stride / 4) + 1) * 4;
            //int k = bmp.Height * stride;
            //byte[] buf = new byte[k];
            //for (int j = 0; j < bmp.Height; j++)
            //{
            //    k = j * stride;//因图像宽度不同、有的可能有填充字节需要跳越
            //    int x = 0, ab = 0;
            //    for (int i = 0; i < bmp.Width; i++)
            //    {
            //        //从灰度变单色（下法如果直接从彩色变单色效果不太好，不过反相也可以在这里控制）
            //        if ((bmp.GetPixel(i, j)).ToArgb() > midrgb) ab = ab * 2 + 1; else ab = ab * 2;
            //        x++;
            //        if (x == 8)
            //        {
            //            buf[k++] = (byte)ab;
            //            ab = 0;
            //            x = 0;
            //        }
            //    }
            //    if (x > 0)
            //    {
            //        //循环实现：剩余有效数据不满1字节的情况下须把它们移往字节的高位部分
            //        for (int t = x; t < 8; t++) ab = ab * 2;
            //        buf[k++] = (byte)ab;
            //    }
            //}
            //Bitmap bitmap_to_save = new Bitmap(img.Width, img.Height, PixelFormat.Format1bppIndexed);
            //BitmapData dt = bitmap_to_save.LockBits(new Rectangle(0, 0, bitmap_to_save.Width, bitmap_to_save.Height), ImageLockMode.ReadWrite, bitmap_to_save.PixelFormat);
            //Marshal.Copy(buf, 0, dt.Scan0, buf.Length);
            //bitmap_to_save.UnlockBits(dt);
            ////bb.MakeTransparent(Color.White);
            ///* 如果需要生成透明的单色图像，必须根据背景颜色不同，在此指定不同颜色为透明。
            //* 但是带透明的PNG不再是单色PNG格式，文件尺寸也更大一些。
            //* 在此是以原图黑底白字的为例，因为经过上面反相以后背景已变成白色，所以这里
            //* 指定了白色为透明色；反之应当指定黑色为透明。
            //* 注意：如果原图是透明背景白字的，等同黑底白字，这段代码全部不需要修改，可
            //* 以反相输出透明背景黑字的。但是，如果原图是透明背景黑字的，上面就不能用矩
            //* 阵做反相，否则由于变成全黑而最后输出无字透明；
            //* 因此，只需Graphics那里改成不使用ImageAttribute参数的DrawImage画出白色背景
            //* 黑字，然后这里不用改变就仍然输出原样的透明背景黑字；
            //* 如果一定要求把它反相成透明背景白字的（一般也没有这种需要），只要在上面循环
            //* 里注释着从灰度变单色的地方把if条件的>号改成<号，这里改成指定黑色为透明即可。
            //*/
            ////保存时若不指定第2参数，单色位图默认地被以单色PNG格式保存。虽然是单色像素格式，
            ////不影响保存为GIF文件或者非索引色图片，只不过GIF不能指定透明色，否则全黑。
            //bitmap_to_save.Save("w.bmp", ImageFormat.Bmp);
            //// 打开保存的BMP文件
            //Bitmap bmp_3 = new Bitmap("scale_ruler_1bit.bmp");
            //Bitmap bmp_2 = new Bitmap("w.bmp");
            //bmp_2.Dispose();
            //bmp_3.Dispose();
            //bitmap_to_save.Dispose();
            //bmp.Dispose();
            //img.Dispose();



            #endregion

            /// 用画图工具打开bmp另存为一份新的
            #region method2
            int index = SwitchRulerComboBox.SelectedIndex == -1 ? 0 : SwitchRulerComboBox.SelectedIndex;

            OpenAndSaveAsMonoBmp($"output\\scale_ruler_{index}_1bit.bmp", $"output\\scale_ruler_{index}_1bit_3.bmp");
            #endregion
        }
        public bool IsNumeric(string str)
        {
            //写正则表达式，只能输入数字&小数
            string regexString = @"(^[0-9]*[1-9][0-9]*$)|(^([0-9]{1,}[.][0-9]*)$)";
            Match m = Regex.Match(str, regexString);

            if (m.Success)
            {
                //是数字
                return true;
            }
            else
            {
                //不是数字
                return false;
            }
        }

        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                // 处理回车键按下的逻辑
                if (IsNumeric(textBox1.Text))
                {
                    unit = float.Parse(textBox1.Text);
                    pictureBox1.Invalidate();
                }
                else
                    MessageBox.Show("文本框里只能为数字");
            }
        }

        private void SwitchRulerComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {

            pictureBox1.Invalidate();
        }
        public void OpenAndSaveAsMonoBmp(string originalFilePath, string newFilePath)
        {
            // 打开画图软件
            Process paintProcess = new Process();
            paintProcess.StartInfo.FileName = "mspaint.exe";
            paintProcess.Start();

            // 等待画图软件打开
            paintProcess.WaitForInputIdle();

            // 执行画图软件的命令行操作
            string commandLineArgs = string.Format("\"{0}\"", originalFilePath);
            ProcessStartInfo processStartInfo = new ProcessStartInfo();
            processStartInfo.FileName = "mspaint.exe";
            processStartInfo.Arguments = commandLineArgs;
            Process.Start(processStartInfo).WaitForExit();

            // 关闭画图软件
            paintProcess.Kill();
        }
    }
}
